// 查看和保存轮廓
#include "tabwin1.h"
#include "ui_tabwin1.h"
#include <QMenu>

using namespace cv;

// 初始化
void TabWin1::init1(){
    timer=new QTimer();
    timer->setInterval(500);
    connect(timer, &QTimer::timeout, this, [=](){
        if(srcImage.empty()) return;
        // 列表
        if(contours.empty()||ui->tabWidget->currentIndex()!=0){
            standItemModel->clear();
        }else{
            // 轮廓和索引// 保存到列表中
            ui->tableView->setUpdatesEnabled(0);
            ui->tableView->setSortingEnabled(false);
            standItemModel->setHorizontalHeaderLabels({"轮廓面积","轮廓特征"});
            for (size_t i = 0; i < contours.size(); ++i) {
                QString contourStr;
                for (int n = 0; n < contours[i].size(); ++n) {
                    contourStr+=QString::number(contours[i][n].x)+","+QString::number(contours[i][n].y)+";";
                }
                QStandardItem *item=new QStandardItem(QString::number(contourArea(contours[i])));
                item->setData(contourArea(contours[i]), Qt::EditRole);  // 根据数值排序
                standItemModel->setItem(i, 0, item);
                standItemModel->setItem(i, 1, new QStandardItem(contourStr));
            }
            while (standItemModel->rowCount()>contours.size()) {
                standItemModel->removeRow(standItemModel->rowCount()-1);
            }
            ui->tableView->resizeColumnToContents(0);
            ui->tableView->setUpdatesEnabled(1);
            ui->tableView->setSortingEnabled(true);
        }
        timer->stop();
    });
    // // //表格
    standItemModel = new QStandardItemModel();
    ui->tableView->setModel(standItemModel);                                            //挂载表格模型
    // 设置表格属性
    ui->tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);              //表头信息显示居中
    ui->tableView->setEditTriggers(QAbstractItemView::SelectedClicked);                 //设置表格属性(如只读，不能编辑)
    ui->tableView->setSelectionBehavior(QTableView::SelectRows);                        //整行选中
    ui->tableView->resizeColumnToContents(0);
    ui->tableView->scrollToBottom();
    ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->tableView, &QTableView::customContextMenuRequested
            , this, &TabWin1::on_tableViewCustomContextMenuRequested);
    ui->spinBox->setValue(0);
    ui->spinBox_2->setValue(155);
    ui->spinBox_3->setValue(110);
    ui->spinBox_13->setValue(10);
    ui->spinBox_14->setValue(255);
    ui->spinBox_15->setValue(255);
}

void TabWin1::opencv_test(){
    if(srcImage.empty()) return;
    timer->stop();
    cv::Mat hsv, image, mask;
    double scale = (double)ui->horizontalSlider_16->value()/100.0f;  // 缩放比例，根据需要调整
    cv::resize(srcImage, image, cv::Size(), scale, scale, cv::INTER_LINEAR);
    // 使用边缘
    if(edge_method){
        cv::cvtColor(image, image, cv::COLOR_BGR2GRAY);
        EdgeMethod(image, hsv, edge_method);
    }else{
        cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
    }
    showImage("source image", hsv);
    // 如果列表为空使用实时调节的值，不为空则使用阈值数组
    if(listModel->rowCount()<1){
        cv::Scalar lower_red(ui->spinBox->value()/2, ui->spinBox_2->value(), ui->spinBox_3->value()); // 下限
        cv::Scalar upper_red(ui->spinBox_13->value()/2, ui->spinBox_14->value(), ui->spinBox_15->value()); // 上限
        cv::inRange(hsv, lower_red, upper_red, mask);
    }else{
        std::vector<cv::Scalar> lowerBounds;
        std::vector<cv::Scalar> upperBounds;
        for (int i = 0; i < listModel->rowCount(); ++i) {
            QString str = listModel->item(i)->text();
            QList<QString> v_str = str.split(",");
            if(v_str.size()!=6) continue;
            lowerBounds.push_back(cv::Scalar(v_str[0].toInt(), v_str[1].toInt(), v_str[2].toInt()));
            upperBounds.push_back(cv::Scalar(v_str[3].toInt(), v_str[4].toInt(), v_str[5].toInt()));
        }
        if(lowerBounds.empty()) return;
        cv::Mat combined_mask;
        for (size_t i = 0; i < lowerBounds.size(); ++i) {
            cv::Mat maskTmp;
            cv::inRange(hsv, lowerBounds[i], upperBounds[i], maskTmp);
            if (i == 0) {
                combined_mask = maskTmp.clone();
            } else {
                cv::bitwise_or(combined_mask, maskTmp, combined_mask);
            }
        }
        mask = combined_mask.clone();
    }
    showImage("inRange mask", mask);
    // 提取轮廓
    std::vector<std::vector<cv::Point>> contours_tmp;
    cv::findContours(mask, contours_tmp, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    cv::Mat drawing = image.clone();
    // 绘制轮廓和索引文本
    for (size_t i = 0; i < contours_tmp.size(); ++i) {
        cv::drawContours(drawing, contours_tmp, (int)i, cv::Scalar(0, 255, 0), 2);
        cv::Point textPos = cv::Point(contours_tmp[i].at(0).x + 6, contours_tmp[i].at(0).y - 6);
        cv::putText(drawing, std::to_string(i+1), textPos, cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(255, 106, 106), 1, LINE_AA);
    }
    contours_tmp.swap(contours);
    showImage("Contours", drawing);
    timer->start();
}

// 边缘检测方式
void TabWin1::EdgeMethod(InputArray src, OutputArray dst, int method)
{
    if(src.empty()) return;
    cv::Mat edge;
    if(1==method){
        // Prewitt算子
        Mat kernelPrewittX = (cv::Mat_<float>(3, 3) << -1, 0, 1, -1, 0, 1, -1, 0, 1);
        Mat kernelPrewittY = (cv::Mat_<float>(3, 3) << -1, -1, -1, 0, 0, 0, 1, 1, 1);
        Mat dstPrewittX, dstPrewittY;
        cv::filter2D(src, dstPrewittX, -1, kernelPrewittX);
        cv::filter2D(src, dstPrewittY, -1, kernelPrewittY);
        cv::abs(dstPrewittX);
        cv::abs(dstPrewittY);
        cv::add(dstPrewittX, dstPrewittY, edge);
        //imshow("prewitt", edge);
    }

    // Sobel算子
    if(2==method){
        Mat dstSobelX, dstSobelY;
        Sobel(src, dstSobelX, CV_16S, 1, 0, 3);
        Sobel(src, dstSobelY, CV_16S, 0, 1, 3);
        convertScaleAbs(dstSobelX, dstSobelX);
        convertScaleAbs(dstSobelY, dstSobelY);
        cv::add(dstSobelX, dstSobelY, edge);
        //imshow("Sobel", edge);
    }

    // Canny算子
    if(3==method){
        blur(src, edge, Size(3, 3));
        Canny(edge, edge, 3, 9, 3);
        //imshow("Canny", edge);
    }

    // Laplacian算子
    if(4==method){
        Laplacian(src, edge, CV_16S, 3);
        convertScaleAbs(edge, edge);
        //imshow("Laplacian", edge);
    }

    edge.copyTo(dst);
}

// 导出轮廓特征
void TabWin1::ExportData(){
    QString selectedFile = QFileDialog::getSaveFileName(this, "Save File", QDir::homePath(), "contours data(*.txt);");
    if (!selectedFile.isEmpty()) {
        QFile file(selectedFile);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
            this->setStatusTip("轮廓特征导出失败！(无法打开文件)");
            return ; // 如果文件无法打开，返回false
        }
        QTextStream out(&file);
        // 先保存Scalar范围
        out << ui->spinBox->value() << ";" << ui->spinBox_2->value() << ";" << ui->spinBox_3->value() << ";" << ui->spinBox_13->value() << ";" << ui->spinBox_14->value() << ";" << ui->spinBox_15->value() << ";" << ui->horizontalSlider_16->value() << "\n";
        // 保存特征
        QItemSelectionModel* selectionModel = ui->tableView->selectionModel();
        QModelIndexList selectedIndexes = selectionModel->selectedRows();
        foreach (QModelIndex index, selectedIndexes) {
            QString str;
            for (int col = 0; col < standItemModel->columnCount(); ++col) {
                str = str+standItemModel->item(index.row(), col)->text() + ((col==standItemModel->columnCount()-1)?"":"\t");
            }
            out << str << "\n";
        }
        file.close();
        this->setStatusTip("轮廓特征导出成功。");
    }
}

// 标记轮廓特征
void TabWin1::signContours(){
    if(srcImage.empty()) return;
    QTableView *view = ui->tableView;
    if(0==ui->tabWidget->currentIndex()){
        view = ui->tableView;
    }else if(1==ui->tabWidget->currentIndex()){
        view = ui->tableView_2;
    }
    cv::Mat drawing;
    double scale = (double)ui->horizontalSlider_16->value()/100;
    cv::resize(srcImage, drawing, cv::Size(), scale, scale, cv::INTER_LINEAR);
    QModelIndexList selectedIndexes = view->selectionModel()->selectedRows();
    std::vector<std::vector<cv::Point>> v_contours; // 保存轮廓
    foreach (QModelIndex var, selectedIndexes) {
        QString data=view->model()->index(var.row(), 1).data().toString();
        std::vector<cv::Point> coutour;
        if(itemToContour(data, coutour)){
            v_contours.push_back(coutour);
            cv::Point textPos = cv::Point(coutour[coutour.size()-1].x + 6, coutour[coutour.size()-1].y - 6);
            cv::putText(drawing, std::to_string(var.row()+1), textPos, cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(255, 255, 255), 2, LINE_AA);
        }
    }
    cv::drawContours(drawing, v_contours, -1, cv::Scalar(0, 255, 0), 2);
    showImage("select row", drawing);
}

// 表格1右键选项
void TabWin1::on_tableViewCustomContextMenuRequested(const QPoint &pos)
{
    Q_UNUSED(pos);
    QMenu menu;
    //添加右键菜单的选项
    menu.addAction("导出选中");
    menu.addAction("标记选中");
    menu.addAction("添加到对比列表");
    menu.addAction("...");
    connect(&menu, &QMenu::triggered, [=](QAction *action){
        if("导出选中"==action->text()){
            ExportData();
        }else if("标记选中"==action->text()){
            signContours();
        }
        else if("添加到对比列表"==action->text()){
            ui->tableView_2->setSortingEnabled(0);
            QItemSelectionModel* selectionModel = ui->tableView->selectionModel();
            QModelIndexList selectedIndexes = selectionModel->selectedRows();
            foreach (QModelIndex index, selectedIndexes) {
                QString str;
                int row=standItemModel2->rowCount();
                for (int col = 0; col < standItemModel->columnCount(); ++col) {
                    if(col==0){
                        QStandardItem *item=new QStandardItem(standItemModel->item(index.row(), col)->text());
                        item->setData(standItemModel->item(index.row(), col)->text().toDouble(), Qt::EditRole);  // 根据数值排序
                        standItemModel2->setItem(row, col, item);
                        continue;
                    }
                    standItemModel2->setItem(row, col, new QStandardItem(standItemModel->item(index.row(), col)->text()));
                }
            }
            ui->tableView_2->resizeColumnToContents(0);
            ui->tableView_2->setSortingEnabled(1);
            ui->tabWidget->setCurrentIndex(1);
        }
    });
    // 显示menu菜单并设置其显示位置为鼠标位置
    menu.exec(QCursor::pos());
}

// 添加阈值到列表中
void TabWin1::on_pushButton_6_clicked()
{
    QString str=QString("%1,%2,%3,%4,%5,%6").arg(ui->horizontalSlider->value()).arg(ui->horizontalSlider_2->value()).arg(ui->horizontalSlider_3->value()).arg(ui->horizontalSlider_13->value()).arg(ui->horizontalSlider_14->value()).arg(ui->horizontalSlider_15->value());
    for (int i = 0; i < listModel->rowCount(); ++i) {
        QString strTmp = listModel->item(i)->text();
        if(str==strTmp) return;
    }
    listModel->appendRow(new QStandardItem(str));
    // 选择最后一项
    if (listModel->rowCount() > 0){
        ui->listView->selectionModel()->select(listModel->index(listModel->rowCount() - 1, 0), QItemSelectionModel::ClearAndSelect);
        ui->listView->selectionModel()->setCurrentIndex(listModel->index(listModel->rowCount() - 1, 0), QItemSelectionModel::ClearAndSelect);
    }
    opencv_test();
}

// 列表转到阈值
void TabWin1::on_pushButton_clicked()
{
    QModelIndex index = ui->listView->selectionModel()->currentIndex();
    if(!index.isValid()) return;
    QString str = listModel->itemFromIndex(index)->text();
    QList<QString> v_str = str.split(",");
    if(v_str.size()!=6) return;
    ui->horizontalSlider->setValue(v_str[0].toInt());
    ui->spinBox->setValue(v_str[0].toInt());
    ui->horizontalSlider_2->setValue(v_str[1].toInt());
    ui->spinBox_2->setValue(v_str[1].toInt());
    ui->horizontalSlider_3->setValue(v_str[2].toInt());
    ui->spinBox_3->setValue(v_str[2].toInt());
    ui->horizontalSlider_13->setValue(v_str[3].toInt());
    ui->spinBox_13->setValue(v_str[3].toInt());
    ui->horizontalSlider_14->setValue(v_str[4].toInt());
    ui->spinBox_14->setValue(v_str[4].toInt());
    ui->horizontalSlider_15->setValue(v_str[5].toInt());
    ui->spinBox_15->setValue(v_str[5].toInt());
}

// 删除行
void TabWin1::on_pushButton_7_clicked()
{
    QModelIndex index = ui->listView->selectionModel()->currentIndex();
    if(!index.isValid()) return;
    listModel->removeRow(index.row());
    // 选择下一项
    index = listModel->index(index.row(), 0);
    if(!index.isValid()) return;
    ui->listView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
    ui->listView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
    opencv_test();
}

